package org.dynamo.database.reverse.config.internal;
/*******************************************************************************
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Jean Neveux - initial API and implementation
 *******************************************************************************/

import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.dynamo.database.reverse.config.internal.log.Log;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.EcoreResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.uml2.uml.Element;
import org.eclipse.uml2.uml.Model;
import org.eclipse.uml2.uml.Package;
import org.eclipse.uml2.uml.PackageImport;
import org.eclipse.uml2.uml.UMLFactory;
import org.eclipse.uml2.uml.UMLPackage;
import org.eclipse.uml2.uml.resource.UMLResource;
import org.eclipse.uml2.uml.util.UMLUtil;

public class UMLResources {
	private static final Log log = Log.getLog(UMLResources.class);
	
	private ResourceSet resourceSet;
	private Map<URI, URI> uriMap;

	private void registerXMIFactory() {
		EPackage.Registry.INSTANCE.put("http:///org/eclipse/uml2.ecore",
				UMLPackage.eINSTANCE);
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
				"uml", UMLResource.Factory.INSTANCE);
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put(
				"ecore", new EcoreResourceFactoryImpl());
		Resource.Factory.Registry.INSTANCE.getExtensionToFactoryMap().put("*",
				new XMIResourceFactoryImpl());
	}
	
	/**
	 * Build UML Resources, and append standards profiles.
	 */
	public UMLResources()
	{
		resourceSet = new ResourceSetImpl();
		registerXMIFactory();
		resourceSet.getPackageRegistry().put(UMLPackage.eNS_URI,
				UMLPackage.eINSTANCE);
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
				.put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);
		uriMap = resourceSet.getURIConverter().getURIMap();
		String location = Platform.getBundle("org.eclipse.uml2.uml.resources")
					.getLocation();
		URI uri = URI.createURI(location);
		uriMap.put(URI.createURI(UMLResource.LIBRARIES_PATHMAP), uri
				.appendSegment("libraries").appendSegment(""));
		uriMap.put(URI.createURI(UMLResource.METAMODELS_PATHMAP), uri
				.appendSegment("metamodels").appendSegment(""));
		uriMap.put(URI.createURI(UMLResource.PROFILES_PATHMAP), uri
				.appendSegment("profiles").appendSegment(""));
		resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
				.put(UMLResource.FILE_EXTENSION, UMLResource.Factory.INSTANCE);
	}

	/**
	 * Get the ResourceSet
	 * @return {@link ResourceSet}
	 * @see ResourceSet
	 */
	public ResourceSet getResourceSet() {
		return resourceSet;
	}
	
	private static Map<String, String> getSaveOptions() {
		Map<String, String> saveOptions = new HashMap<String, String>();
		saveOptions.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
		saveOptions.put(Resource.OPTION_SAVE_ONLY_IF_CHANGED,
				Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER);
		return saveOptions;
	}
	
	/**
	 * Save an UML model.
	 * 
	 * @param path
	 *            {@link String} relative path to the project.
	 * @param model
	 *            {@link Model} the UML model to save.
	 */
	public static void save(String path, Model model) {
		URI fileURI = URI.createPlatformResourceURI(path,true);
		Resource resource = UMLResource.Factory.INSTANCE
				.createResource(fileURI);
		resource.getContents().add(model);
		for (Iterator<EObject> allContents = UMLUtil.getAllContents(model, true,
				false); allContents.hasNext();) {
				EObject eObject = (EObject) allContents.next();
				if (eObject instanceof Element) {
					resource.getContents()
						.addAll(((Element) eObject).getStereotypeApplications());
				}
			}
		try {
			resource.save(getSaveOptions());
		} catch (IOException e) {
			log.error("Saving :" + e.getMessage());
		}
	}
	
	/**
	 * Load and returns the content of an UML module as an UML Package.
	 * @param uri {@link URI}
	 * @return {@link Package}
	 */
	public org.eclipse.uml2.uml.Package contentload(URI uri) {
		org.eclipse.uml2.uml.Package package_ = null;
		try {
			Resource modelResource = resourceSet.getResource(uri, true);
			package_ = (org.eclipse.uml2.uml.Package) EcoreUtil
					.getObjectByType(modelResource.getContents(),
							UMLPackage.eINSTANCE.getPackage());
		} catch (WrappedException we) {
			log.error("Content load:" + we.getMessage());
		}

		return package_;
	}

	public Map<URI, URI> getUriMap() {
		return uriMap;
	}

	public PackageImport getModelLibraryImportFromURI(URI uriToLoad) {
		Resource modelResource = resourceSet.getResource(uriToLoad, true);
		if (modelResource.getContents().size() <= 0) {
			log.error("No element found in model from URI "
					+ uriToLoad.toString());
			return null;
		}
		Element root = ((Element) modelResource.getContents().get(0));
		if ((root instanceof Package)) {
			Package libToImport = (Package) (modelResource.getContents().get(0));
			PackageImport modelLibImport = UMLFactory.eINSTANCE
					.createPackageImport();
			modelLibImport.setImportedPackage(libToImport);
			return modelLibImport;
		}
		log.error("The selected uri (" + uriToLoad.toString()
				+ ") does not contain any model library !");
		return null;
	}
}
